package com.flying;

import java.io.IOException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.junit.Test;

/**
 * Wacth事件触发的演示!
 * 一句话攻略： 首先只有3个get类型的方法能够设置触发watch
 * exists 触发 目标节点的创建，删除，数据更新
 * getData 比较上面----目标节点除了创建。删除，和更新都可以触发
 * getChildren 子节点的创建和删除会触发NodeChildrenChanged,以及父节点本身的删除.
 */
public class WacthDemo {

    private ZooKeeper connection() throws IOException {
        return new ZooKeeper("localhost:" + 2181, 10000, new Watcher() {
            public void process(WatchedEvent event) {
                if (event.getPath() == null) { //连接时会触发None的事件
                    System.out.println("初始化连接" + event.getType());
                } else if (event.getType() == Event.EventType.NodeDeleted) {
                    System.out.println("[节点删除]" + event.getPath() + ":" + event.getType());
                } else if (event.getType() == Event.EventType.NodeCreated) {
                    System.out.println("[节点创建]" + event.getPath() + ":" + event.getType());
                } else if (event.getType() == Event.EventType.NodeDataChanged) {
                    System.out.println("[节点更新]" + event.getPath() + ":" + event.getType());
                } else if (event.getType() == Event.EventType.NodeChildrenChanged) {
                    System.out.println("[子节点更新(父增删子节点)]" + event.getPath() + ":" + event.getType());
                }
            }
        });
    }

    /**
     * 测试exists事件: --> 被监视的Znode创建(create:NodeCreate)、删除(delete:NodeDelete)、更新(setData:NodeDataChange)时被触发。
     */
    @Test
    public void test1() throws IOException, KeeperException, InterruptedException {
        ZooKeeper zk = connection();
//        Stat stat = zk.exists("/root", true);
//        if (stat == null) {
//            zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
//        }
//        Stat stat2 = zk.exists("/root", true);
//        if (stat2 == null) {
//            zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
//        } else {
//            zk.setData("/root", "haha".getBytes(), -1);//-1好像表示全部版本
//        }
//        //zk.delete("/root",-1); 此时不触发事件，因为一个get类型方法只能触发它对应的事件一次。
//        Stat stat3 = zk.exists("/root", true);
//        if (stat3 != null) {
//            zk.delete("/root", -1);
//        }
        zk.close();
    }


    /**
     * 测试getData事件: --> 被监视的Znode删除(delete:NodeDelete)、更新(setData:NodeDataChange)时被触发。
     *
     * @throws InterruptedException
     * @throws KeeperException
     */
    @Test
    public void test2() throws IOException, KeeperException, InterruptedException {
        ZooKeeper zk = connection();
        Stat stat = zk.exists("/root", false);
        if (stat == null) {
            zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        }
        byte[] data1 = zk.getData("/root", true, null);
        System.out.println(new String(data1));
        zk.setData("/root", "haha".getBytes(), -1); //触发NodeDataChange
        byte[] data2 = zk.getData("/root", true, null);
        System.out.println(new String(data2));
        zk.delete("/root", -1);
    }

    /**
     * 测试getChildren事件:-->父节点下的子增删 (delete:NodeChildrenChanged) 父节点自己的删除 (delete:NodeDelete)
     */
    @Test
    public void test3() throws IOException, KeeperException, InterruptedException {
        ZooKeeper zk = connection();
        Stat stat = zk.exists("/root", false);
        if (stat == null) {
            zk.create("/root", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }
        //---------------------------------------------------------
        zk.getChildren("/root", true);
        zk.create("/root/children1", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        zk.getChildren("/root", true);
        zk.create("/root/children2", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        zk.getChildren("/root", true);
        zk.delete("/root/children1", -1);
        zk.delete("/root/children2", -1);
        zk.getChildren("/root", true);
        zk.delete("/root", -1); /**不能级联删除,要把子节点全删掉！*/
    }
}
 
 